package com.domainlanguage.time;

import static com.domainlanguage.TimeAndMoneyTypes.*;
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.type.Type;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Properties;

/**
 * Hibernate user type for {@link com.domainlanguage.time.CalendarInterval}.
 * <p/>
 * Start and end calendar dates are backed by {@link java.sql.Types.DATE}.
 */
public class CalendarIntervalType extends ImmutableCompositeUserType {

    private static final String[] PROPERRTY_NAMES = {"start", "end"};
    private static final Type[] PROPERTY_TYPES = {CALENDAR_DATE, CALENDAR_DATE};

    @Override
    public String[] getPropertyNames() {
        return PROPERRTY_NAMES;
    }

    @Override
    public Type[] getPropertyTypes() {
        return PROPERTY_TYPES;
    }

    @Override
    public Object getPropertyValue(final Object component, final int property) throws HibernateException {
        final CalendarInterval calendarInterval = (CalendarInterval) component;
        switch (property) {
            case 0:
                return calendarInterval.start();
            case 1:
                return calendarInterval.end();
            default:
                throw new HibernateException(
                    "Property index " + property + " is out of range. Properties are: " +
                        Arrays.toString(getPropertyNames())
                );
        }
    }

    @Override
    public Class returnedClass() {
        return CalendarInterval.class;
    }

    @Override
    public Object nullSafeGet(final ResultSet rs, final String[] names, final SessionImplementor session, Object owner) throws HibernateException, SQLException {
        final CalendarDate start = (CalendarDate) CALENDAR_DATE.nullSafeGet(rs, names[0]);
        final CalendarDate end = (CalendarDate) CALENDAR_DATE.nullSafeGet(rs, names[1]);

        if (start == null || end == null) {
            return null;
        } else {
            // Calendar intervals are always inclusive
            return CalendarInterval.inclusive(start, end);
        }
    }

    @Override
    public void nullSafeSet(final PreparedStatement st, final Object value, final int index, final SessionImplementor session) throws HibernateException, SQLException {
        if (value == null) {
            st.setNull(index, CALENDAR_DATE.sqlType());
            st.setNull(index + 1, CALENDAR_DATE.sqlType());
            return;
        }

        final CalendarInterval calendarInterval = (CalendarInterval) value;
        CALENDAR_DATE.nullSafeSet(st, calendarInterval.start(), index);
        CALENDAR_DATE.nullSafeSet(st, calendarInterval.end(), index + 1);
    }

}